package com.aps.demo;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.StreamWriteConstraints;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * 遗传算法工具类
 * 
 * 提供遗传算法中常用的数学计算和工具方法
 * 
 * @author APS System
 * @version 1.0
 */
@Slf4j
public class GAUtils {
    
    /**
     * 计算阶乘
     * 
     * 用于计算基因序列的全排列数量，帮助确定种群大小
     * 例如：有8个工序，则存在8! = 40320种不同的排列组合
     * 
     * @param n 要计算阶乘的数
     * @return 阶乘结果，如果n过大可能溢出返回Long.MAX_VALUE
     */
    public static long calFactorial(int n) {
        if (n < 0) {
            throw new IllegalArgumentException("阶乘的参数不能为负数");
        }
        if (n == 0 || n == 1) {
            return 1;
        }
        
        long result = 1;
        for (int i = 2; i <= n; i++) {
            // 检查是否会溢出
            if (result > Long.MAX_VALUE / i) {
                return Long.MAX_VALUE; // 返回最大值表示溢出
            }
            result *= i;
        }
        return result;
    }
    
    /**
     * 计算组合数 C(n, r) = n! / (r! * (n-r)!)
     * 
     * 用于计算遗传算法中的选择概率和交叉点数量
     * 
     * @param n 总数
     * @param r 选择数
     * @return 组合数
     */
    public static long combination(int n, int r) {
        if (r < 0 || r > n) {
            return 0;
        }
        if (r == 0 || r == n) {
            return 1;
        }
        
        // 优化：C(n,r) = C(n,n-r)，选择较小的r
        if (r > n - r) {
            r = n - r;
        }
        
        long result = 1;
        for (int i = 0; i < r; i++) {
            result = result * (n - i) / (i + 1);
        }
        return result;
    }
    
    /**
     * 计算适应度值的标准化
     * 
     * 将适应度值映射到[0,1]区间，便于比较和选择
     * 
     * @param fitness 原始适应度值
     * @param minFitness 最小适应度值
     * @param maxFitness 最大适应度值
     * @return 标准化后的适应度值
     */
    public static double normalizeFitness(double fitness, double minFitness, double maxFitness) {
        if (maxFitness == minFitness) {
            return 1.0; // 避免除零错误
        }
        return (fitness - minFitness) / (maxFitness - minFitness);
    }
    
    /**
     * 计算种群的适应度统计信息
     * 
     * @param population 种群
     * @return 适应度统计信息数组 [最小值, 最大值, 平均值, 标准差]
     */
    public static double[] calculateFitnessStatistics(java.util.List<Chromosome> population) {
        if (population == null || population.isEmpty()) {
            return new double[]{0, 0, 0, 0};
        }
        
        double min = Double.MAX_VALUE;
        double max = Double.MIN_VALUE;
        double sum = 0;
        
        for (Chromosome chromosome : population) {
            double fitness = chromosome.getFitness();
            min = Math.min(min, fitness);
            max = Math.max(max, fitness);
            sum += fitness;
        }
        
        double mean = sum / population.size();
        
        // 计算标准差
        double variance = 0;
        for (Chromosome chromosome : population) {
            double diff = chromosome.getFitness() - mean;
            variance += diff * diff;
        }
        double stdDev = Math.sqrt(variance / population.size());
        
        return new double[]{min, max, mean, stdDev};
    }
    
    /**
     * 生成指定范围内的随机整数
     * 
     * @param min 最小值（包含）
     * @param max 最大值（不包含）
     * @return 随机整数
     */
    public static int randomInt(int min, int max) {
        if (min >= max) {
            throw new IllegalArgumentException("最小值必须小于最大值");
        }
        return min + (int) (Math.random() * (max - min));
    }
    
    /**
     * 生成0到1之间的随机双精度数
     * 
     * @return 随机双精度数
     */
    public static double randomDouble() {
        return Math.random();
    }
    
    /**
     * 判断是否应该执行某个概率事件
     * 
     * @param probability 概率值（0.0-1.0）
     * @return 如果应该执行返回true，否则返回false
     */
    public static boolean shouldExecute(double probability) {
        if (probability < 0 || probability > 1) {
            log.info(String.valueOf(probability));
            throw new IllegalArgumentException("概率值必须在0.0到1.0之间");
        }
        return Math.random() < probability;
    }
    
    /**
     * 轮盘赌选择算法
     * 
     * 根据适应度比例随机选择染色体
     * 
     * @param population 种群
     * @return 被选中的染色体索引
     */
    public static int rouletteWheelSelection(java.util.List<Chromosome> population) {
        if (population == null || population.isEmpty()) {
            throw new IllegalArgumentException("种群不能为空");
        }
        
        // 计算适应度总和
        double totalFitness = population.stream()
                .mapToDouble(Chromosome::getFitness)
                .sum();
        
        if (totalFitness <= 0) {
            // 如果所有适应度都为0或负数，随机选择
            return randomInt(0, population.size());
        }
        
        // 生成随机数
        double randomValue = Math.random() * totalFitness;
        
        // 累积概率选择
        double cumulativeFitness = 0;
        for (int i = 0; i < population.size(); i++) {
            cumulativeFitness += population.get(i).getFitness();
            if (cumulativeFitness >= randomValue) {
                return i;
            }
        }
        
        // 理论上不应该到这里，但为了安全返回最后一个
        return population.size() - 1;
    }
    
    /**
     * 计算种群的多样性指标
     * 
     * 通过计算染色体间的差异度来衡量种群多样性
     * 多样性越高，算法越不容易陷入局部最优
     * 
     * @param population 种群
     * @return 多样性指标（0.0-1.0，值越大多样性越高）
     */
    public static double calculateDiversity(java.util.List<Chromosome> population) {
        if (population == null || population.size() < 2) {
            return 0.0;
        }
        
        int totalComparisons = 0;
        int differentPairs = 0;
        
        // 比较每对染色体的基因序列
        for (int i = 0; i < population.size(); i++) {
            for (int j = i + 1; j < population.size(); j++) {
                totalComparisons++;
                if (areDifferentChromosomes(population.get(i), population.get(j))) {
                    differentPairs++;
                }
            }
        }
        
        return totalComparisons > 0 ? (double) differentPairs / totalComparisons : 0.0;
    }
    
    /**
     * 判断两个染色体是否不同
     * 
     * @param c1 染色体1
     * @param c2 染色体2
     * @return 如果染色体不同返回true
     */
    private static boolean areDifferentChromosomes(Chromosome c1, Chromosome c2) {
        if (c1.getGeneLength() != c2.getGeneLength()) {
            return true;
        }
        
        // 比较基因序列
        for (int i = 0; i < c1.getGeneLength(); i++) {
            String gene1 = c1.getGeneSequence().get(i).getId();
            String gene2 = c2.getGeneSequence().get(i).getId();
            if (!gene1.equals(gene2)) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 检测种群是否收敛
     * 
     * 当种群中大部分个体适应度相近时，认为种群已收敛
     * 
     * @param population 种群
     * @param convergenceThreshold 收敛阈值（0.0-1.0）
     * @return 如果种群已收敛返回true
     */
    public static boolean isPopulationConverged(java.util.List<Chromosome> population, double convergenceThreshold) {
        if (population == null || population.isEmpty()) {
            return true;
        }
        
        double[] stats = calculateFitnessStatistics(population);
        double mean = stats[2];
        double stdDev = stats[3];
        
        // 如果标准差相对于平均值很小，则认为收敛
        if (mean == 0) {
            return stdDev < convergenceThreshold;
        }
        
        double coefficientOfVariation = stdDev / Math.abs(mean);
        return coefficientOfVariation < convergenceThreshold;
    }
    
    /**
     * 计算动态种群大小
     * 
     * 根据问题复杂度（基因数量）动态调整种群大小
     * 
     * @param geneCount 基因数量（工序数量）
     * @param minPopSize 最小种群大小
     * @param maxPopSize 最大种群大小
     * @return 建议的种群大小
     */
    public static int calculateDynamicPopulationSize(int geneCount, int minPopSize, int maxPopSize) {
        if (geneCount <= 0) {
            return minPopSize;
        }
        
        // 基于经验公式：种群大小 ≈ 基因数量 × 2.5，但限制在最小和最大值之间
        int suggestedSize = (int) Math.ceil(geneCount * 10);
        
        return Math.max(minPopSize, Math.min(maxPopSize, suggestedSize));
    }
    
    /**
     * 计算自适应交叉率
     * 
     * 根据种群多样性和进化代数动态调整交叉率
     * 多样性高时降低交叉率保持稳定性，多样性低时提高交叉率促进探索
     * 
     * @param diversity 种群多样性（0.0-1.0）
     * @param generation 当前代数
     * @param maxGenerations 最大代数
     * @param baseCrossoverRate 基础交叉率
     * @return 自适应交叉率
     */
    public static double calculateAdaptiveCrossoverRate(double diversity, int generation, 
                                                       int maxGenerations, double baseCrossoverRate) {
        // 基于多样性的调整：多样性低时增加交叉率
        double diversityFactor = 1.0 + (0.5 - diversity); // 多样性0.5时不调整，低于0.5时增加
        
        // 基于进化进程的调整：后期适当降低交叉率，增加稳定性
        double progressFactor = 1.0 - 0.3 * ((double) generation / maxGenerations);
        
        double adaptiveRate = baseCrossoverRate * diversityFactor * progressFactor;
        
        // 限制在合理范围内
        return Math.max(0.5, Math.min(0.95, adaptiveRate));
    }
    
    /**
     * 计算自适应变异率
     * 
     * 根据种群多样性和收敛状况动态调整变异率
     * 
     * @param diversity 种群多样性（0.0-1.0）
     * @param fitnessImprovement 最近几代的适应度改进幅度
     * @param baseMutationRate 基础变异率
     * @return 自适应变异率
     */
    public static double calculateAdaptiveMutationRate(double diversity, double fitnessImprovement, 
                                                      double baseMutationRate) {
        // 基于多样性的调整：多样性低时增加变异率
        double diversityFactor = 2.0 - diversity; // 多样性1.0时因子为1.0，多样性0.0时因子为2.0
        
        // 基于适应度改进的调整：改进缓慢时增加变异率
        double improvementFactor = fitnessImprovement < 0.001 ? 1.5 : 1.0;
        
        double adaptiveRate = baseMutationRate * diversityFactor * improvementFactor;
        
        // 限制在合理范围内
        return Math.max(0.01, Math.min(0.2, adaptiveRate));
    }
    
    /**
     * 锦标赛选择（支持多样性保护）
     * 
     * @param population 种群
     * @param tournamentSize 锦标赛大小
     * @param diversityWeight 多样性权重（0.0-1.0）
     * @return 选中的染色体索引
     */
    public static int tournamentSelectionWithDiversity(java.util.List<Chromosome> population, 
                                                      int tournamentSize, double diversityWeight) {
        if (population == null || population.isEmpty()) {
            throw new IllegalArgumentException("种群不能为空");
        }
        
        int bestIndex = -1;
        double bestScore = Double.NEGATIVE_INFINITY;
        
        for (int i = 0; i < tournamentSize; i++) {
            int candidateIndex = randomInt(0, population.size());
            Chromosome candidate = population.get(candidateIndex);
            
            // 计算综合评分：适应度 + 多样性奖励
            double fitnessScore = candidate.getFitness();
            double diversityBonus = calculateDiversityBonus(candidate, population) * diversityWeight;
            double totalScore = fitnessScore + diversityBonus;
            
            if (totalScore > bestScore) {
                bestScore = totalScore;
                bestIndex = candidateIndex;
            }
        }
        
        return bestIndex != -1 ? bestIndex : randomInt(0, population.size());
    }
    
    /**
     * 计算染色体的多样性奖励
     * 
     * @param chromosome 目标染色体
     * @param population 种群
     * @return 多样性奖励值
     */
    private static double calculateDiversityBonus(Chromosome chromosome, java.util.List<Chromosome> population) {
        int differentCount = 0;
        for (Chromosome other : population) {
            if (areDifferentChromosomes(chromosome, other)) {
                differentCount++;
            }
        }
        return (double) differentCount / population.size();
    }
    
    /**
     * 生成高斯分布随机数
     * 
     * @param mean 均值
     * @param stdDev 标准差
     * @return 高斯分布随机数
     */
    public static double gaussianRandom(double mean, double stdDev) {
        return mean + stdDev * new java.util.Random().nextGaussian();
    }
    public static List<List<Operation>>  getPermutationsList(List<Operation> datas){
        List<List<Operation>> result = new ArrayList<>();
        getPermutations(datas, 0, result);
        return result;
    }


    public static void getPermutations(List<Operation> datas , int start, List<List<Operation>> result) {
        if (start == datas.size()) {
            List<Operation> temp = new ArrayList<>();
            for (Operation data : datas) {
                Operation aps = new Operation();
                BeanUtils.copyProperties(data, aps);
                aps.newInstanceProperty();
                temp.add(aps);
            }
            result.add(new ArrayList<>(temp));
            return;
        }
        for (int i = start; i < datas.size(); i++) {
            // 交换元素
            Collections.swap(datas, start, i);
            // 递归生成剩余排列
            getPermutations(datas, start + 1, result);
            // 恢复原状
            Collections.swap(datas, start, i);
        }
    }
}